﻿using SD.Common;
using SD.Infrastructure.EntityBase;
using SlamDunk.ValueObjects.Enums;
using SlamDunk.ValueObjects.Interfaces;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SlamDunk.MES.Domain.Entities.ResourceContext
{
    /// <summary>
    /// 物料定义
    /// </summary>
    public class Material : AggregateRootEntity, IDisable
    {
        #region # 构造器

        #region 00.无参构造器
        /// <summary>
        /// 无参构造器
        /// </summary>
        protected Material()
        {
            //初始化导航属性
            this.RelatedClasses = new HashSet<MaterialRelatedClass>();

            //默认值
            this.Enabled = true;
        }
        #endregion

        #region 01.创建物料定义构造器
        /// <summary>
        /// 创建物料定义构造器
        /// </summary>
        /// <param name="materialNo">物料定义编号</param>
        /// <param name="materialName">物料定义名称</param>
        /// <param name="erpNo">ERP编号</param>
        /// <param name="standardUnitNo">基准单位编号</param>
        /// <param name="specification">规格</param>
        /// <param name="guaranteePeriod">保质期</param>
        /// <param name="materialSourceType">物料来源类型</param>
        /// <param name="hasLot">是否按批量管理</param>
        /// <param name="facilityId">工厂模型Id</param>
        /// <param name="dataSource">数据来源</param>
        /// <param name="description">描述</param>
        public Material(string materialNo, string materialName, string erpNo, string standardUnitNo, string specification, TimeSpan guaranteePeriod, MaterialSourceType? materialSourceType, bool hasLot, Guid? facilityId, string dataSource, string description)
            : this()
        {
            base.Number = materialNo;
            base.Name = materialName;
            this.ErpNo = erpNo;
            this.StandardUnitNo = standardUnitNo;
            this.Specification = specification;
            this.GuaranteePeriodTicks = guaranteePeriod.Ticks;
            this.MaterialSourceType = materialSourceType;
            this.HasLot = hasLot;
            this.FacilityId = facilityId;
            this.DataSource = dataSource;
            this.Description = description;

            //初始化关键字
            this.InitKeywords();
        }
        #endregion

        #endregion

        #region # 属性

        #region ERP编号 —— string ErpNo
        /// <summary>
        /// ERP编号
        /// </summary>
        public string ErpNo { get; private set; }
        #endregion

        #region 基准单位编号 —— string StandardUnitNo
        /// <summary>
        /// 基准单位编号
        /// </summary>
        public string StandardUnitNo { get; private set; }
        #endregion

        #region 规格 —— string Specification
        /// <summary>
        /// 规格
        /// </summary>
        public string Specification { get; private set; }
        #endregion

        #region 保质期 —— TimeSpan GuaranteePeriod
        /// <summary>
        /// 保质期
        /// </summary>
        public long GuaranteePeriodTicks { get; private set; }

        /// <summary>
        /// 保质期
        /// </summary>
        public TimeSpan GuaranteePeriod
        {
            get => TimeSpan.FromTicks(this.GuaranteePeriodTicks);
        }
        #endregion

        #region 物料来源 —— MaterialSourceType? MaterialSourceType
        /// <summary>
        /// 物料来源
        /// </summary>
        public MaterialSourceType? MaterialSourceType { get; private set; }
        #endregion

        #region 是否按批次管理 —— bool HasLot
        /// <summary>
        /// 是否按批次管理
        /// </summary>
        public bool HasLot { get; private set; }
        #endregion

        #region 工厂模型Id —— Guid? FacilityId
        /// <summary>
        /// 工厂模型Id
        /// </summary>
        public Guid? FacilityId { get; private set; }
        #endregion

        #region 数据来源 —— string DataSource
        /// <summary>
        /// 数据来源
        /// </summary>
        public string DataSource { get; private set; }
        #endregion

        #region 是否启用 —— bool Enabled
        /// <summary>
        /// 是否启用
        /// </summary>
        public bool Enabled { get; set; }
        #endregion

        #region 启用人账号 —— string EnablerAccount
        /// <summary>
        /// 启用人账号
        /// </summary>
        public string EnablerAccount { get; set; }
        #endregion

        #region 启用人姓名 —— string EnablerName
        /// <summary>
        /// 启用人姓名
        /// </summary>
        public string EnablerName { get; set; }
        #endregion

        #region 停用人账号 —— string DisablerAccount
        /// <summary>
        /// 停用人账号
        /// </summary>
        public string DisablerAccount { get; set; }
        #endregion

        #region 停用人姓名 —— string DisablerName
        /// <summary>
        /// 停用人姓名
        /// </summary>
        public string DisablerName { get; set; }
        #endregion

        #region 停用原因 —— string DisabledReason
        /// <summary>
        /// 停用原因
        /// </summary>
        public string DisabledReason { get; set; }
        #endregion

        #region 描述 —— string Description
        /// <summary>
        /// 描述
        /// </summary>
        public string Description { get; private set; }
        #endregion

        #region 只读属性 - 所属物料类Id集 —— IEnumerable<Guid> RelatedClassIds
        /// <summary>
        /// 只读属性 - 所属物料类Id集
        /// </summary>
        public IEnumerable<Guid> RelatedClassIds
        {
            get { return this.RelatedClasses.Select(x => x.MaterialClassId); }
        }
        #endregion

        #region 导航属性 - 物料包装 —— MaterialPack MaterialPack
        /// <summary>
        /// 导航属性 - 物料包装
        /// </summary>
        public virtual MaterialPack MaterialPack { get; private set; }
        #endregion

        #region 导航属性 - 物料条码设置 —— MaterialBarcodeSetting MaterialBarcodeSetting
        /// <summary>
        /// 导航属性 - 物料条码设置
        /// </summary>
        public virtual MaterialBarcodeSetting MaterialBarcodeSetting { get; private set; }
        #endregion

        #region 导航属性 - 物料定义相关物料类集 —— ICollection<MaterialRelatedClass> RelatedClasses
        /// <summary>
        /// 导航属性 - 物料定义相关物料类集
        /// </summary>
        public virtual ICollection<MaterialRelatedClass> RelatedClasses { get; private set; }
        #endregion

        #endregion

        #region # 方法

        #region 修改物料定义 —— void UpdateInfo(string materialNo, string materialName...
        /// <summary>
        /// 修改物料定义
        /// </summary>
        /// <param name="materialNo">物料定义编号</param>
        /// <param name="materialName">物料定义名称</param>
        /// <param name="erpNo">ERP编号</param>
        /// <param name="standardUnitNo">基准单位编号</param>
        /// <param name="specification">规格</param>
        /// <param name="guaranteePeriod">保质期</param>
        /// <param name="materialSourceType">物料来源类型</param>
        /// <param name="hasLot">是否按批量管理</param>
        /// <param name="facilityId">工厂模型Id</param>
        /// <param name="dataSource">数据来源</param>
        /// <param name="description">描述</param>
        public void UpdateInfo(string materialNo, string materialName, string erpNo, string standardUnitNo, string specification, TimeSpan guaranteePeriod, MaterialSourceType? materialSourceType, bool hasLot, Guid? facilityId, string dataSource, string description)
        {
            base.Number = materialNo;
            base.Name = materialName;
            this.ErpNo = erpNo;
            this.StandardUnitNo = standardUnitNo;
            this.Specification = specification;
            this.GuaranteePeriodTicks = guaranteePeriod.Ticks;
            this.MaterialSourceType = materialSourceType;
            this.HasLot = hasLot;
            this.FacilityId = facilityId;
            this.DataSource = dataSource;
            this.Description = description;

            //初始化关键字
            this.InitKeywords();
        }
        #endregion

        #region 设置物料包装 —— void SetMaterialPack(MaterialPack materialPack)
        /// <summary>
        /// 设置物料包装
        /// </summary>
        /// <param name="materialPack">物料包装</param>
        public void SetMaterialPack(MaterialPack materialPack)
        {
            if (this.MaterialPack == null)
            {
                this.MaterialPack = materialPack;
                materialPack.Material = this;
            }
            else
            {
                if (materialPack == null)
                {
                    this.MaterialPack = null;
                }
                else
                {
                    this.MaterialPack.Init(materialPack.MaxPack, materialPack.MaxPackCoefficient, materialPack.MinPack, materialPack.MinPackCoefficient);
                }
            }
        }
        #endregion

        #region 设置物料条码设置 —— void SetMaterialBarcodeSetting(MaterialBarcodeSetting...
        /// <summary>
        /// 设置物料条码设置
        /// </summary>
        /// <param name="materialBarcodeSetting">物料条码设置</param>
        public void SetMaterialBarcodeSetting(MaterialBarcodeSetting materialBarcodeSetting)
        {
            if (this.MaterialBarcodeSetting == null)
            {
                this.MaterialBarcodeSetting = materialBarcodeSetting;
                materialBarcodeSetting.Material = this;
            }
            else
            {
                if (materialBarcodeSetting == null)
                {
                    this.MaterialBarcodeSetting = null;
                }
                else
                {
                    this.MaterialBarcodeSetting.Init(materialBarcodeSetting.NeedPrintBarcode, materialBarcodeSetting.BarcodeMode, materialBarcodeSetting.BarcodeUnit);
                }
            }
        }
        #endregion

        #region 关联物料类 —— void RelateClasses(IEnumerable<Guid> materialClassIds)
        /// <summary>
        /// 关联物料类
        /// </summary>
        /// <param name="materialClassIds">物料类Id集</param>
        public void RelateClasses(IEnumerable<Guid> materialClassIds)
        {
            materialClassIds = materialClassIds?.Distinct().ToArray() ?? new Guid[0];

            this.ClearClasses();
            if (materialClassIds.Any())
            {
                MaterialRelatedClass[] relatedClasses = materialClassIds.Select(x => new MaterialRelatedClass(x)).ToArray();
                this.RelatedClasses.AddRange(relatedClasses);
                foreach (MaterialRelatedClass relatedClass in relatedClasses)
                {
                    relatedClass.Material = this;
                }
            }
        }
        #endregion

        #region 启用 —— void Enable(string enablerAccount, string enablerName)
        /// <summary>
        /// 启用
        /// </summary>
        /// <param name="enablerAccount">启用人账号</param>
        /// <param name="enablerName">启用人姓名</param>
        public void Enable(string enablerAccount, string enablerName)
        {
            this.DoEnable(enablerAccount, enablerName);
        }
        #endregion

        #region 停用 —— void Disable(string diablerAccount, string diablerName...
        /// <summary>
        /// 停用
        /// </summary>
        /// <param name="diablerAccount">停用人账号</param>
        /// <param name="diablerName">停用人姓名</param>
        /// <param name="reason">停用原因</param>
        public void Disable(string diablerAccount, string diablerName, string reason)
        {
            this.DoDisable(diablerAccount, diablerName, reason);
        }
        #endregion

        #region 清空物料定义相关物料类 —— void ClearClasses()
        /// <summary>
        /// 清空物料定义相关物料类
        /// </summary>
        private void ClearClasses()
        {
            foreach (MaterialRelatedClass relatedClass in this.RelatedClasses.ToArray())
            {
                this.RelatedClasses.Remove(relatedClass);
            }
        }
        #endregion

        #region 初始化关键字 —— void InitKeywords()
        /// <summary>
        /// 初始化关键字
        /// </summary>
        private void InitKeywords()
        {
            StringBuilder builder = new StringBuilder();
            builder.Append(base.Number);
            builder.Append(base.Name);
            builder.Append(this.ErpNo);
            builder.Append(this.DataSource);
            builder.Append(this.Description);

            base.SetKeywords(builder.ToString());
        }
        #endregion

        #endregion
    }
}
